package net.soevar.action.admins;

import java.util.List;

import net.soevar.action.admins.helper.MenuTreeModel;
import net.soevar.common.Common;
import net.soevar.common.CommonPrivilages;
import net.soevar.database.hibernate.HibernateUtil;
import net.soevar.database.model.AthMenu;
import net.soevar.database.model.AthUser;

import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.util.GenericAutowireComposer;
import org.zkoss.zul.Borderlayout;
import org.zkoss.zul.Center;
import org.zkoss.zul.Checkbox;
import org.zkoss.zul.Column;
import org.zkoss.zul.Columns;
import org.zkoss.zul.Grid;
import org.zkoss.zul.Hbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Row;
import org.zkoss.zul.Rows;
import org.zkoss.zul.South;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Timer;
import org.zkoss.zul.Toolbar;
import org.zkoss.zul.Toolbarbutton;
import org.zkoss.zul.Tree;
import org.zkoss.zul.Treecell;
import org.zkoss.zul.Treechildren;
import org.zkoss.zul.Treecol;
import org.zkoss.zul.Treecols;
import org.zkoss.zul.Treeitem;
import org.zkoss.zul.TreeitemRenderer;
import org.zkoss.zul.Treerow;
import org.zkoss.zul.Window;

public class MenuAction extends GenericAutowireComposer {

	private static final long serialVersionUID = -3352024379118542716L;
	private Window addWindow;

	private static Integer ROOT = 0;

	private Tree tree;

	private Textbox label;
	private Textbox url;
	private Checkbox status;

	private boolean edit;
	private boolean delete;

	private AthMenu menu;
	private boolean add;
	private MenuTreeModel menuTreeModel;

	@Override
	public void doAfterCompose(Component comp) throws Exception {
		super.doAfterCompose(comp);
		AthUser athuser = Common.getCurrentUser();
		if (session.getAttribute("usersTemp") == null
				|| !CommonPrivilages.checkPrevilages(CommonPrivilages.READ)
				|| athuser.getStatusRoot() == null || !athuser.getStatusRoot()) {
			session.removeAttribute("usersTemp");
			execution.sendRedirect("/logoff");
			return;
		}
		add = CommonPrivilages.checkPrevilages(CommonPrivilages.CREATE);
		edit = CommonPrivilages.checkPrevilages(CommonPrivilages.UPDATE);
		delete = CommonPrivilages.checkPrevilages(CommonPrivilages.DELETE);

		initTree();
		onReloadTree(null);
	}

	private void initTree() throws Exception {

		Treecols treecols = new Treecols();
		Treecol treecol = new Treecol("");
		treecol.setWidth("75%");
		treecol.setParent(treecols);

		treecol = new Treecol("");
		treecol.setWidth("10%");
		treecol.setParent(treecols);

		treecol = new Treecol("");
		treecol.setWidth("15%");
		treecol.setParent(treecols);

		treecols.setParent(tree);
	}

	public void onAdd(Event event) throws Exception {

		AthMenu mymenu = new AthMenu();
		mymenu.setRoot(ROOT);

		Session session = HibernateUtil.currentSession();
		Number max = ((Number) session.createCriteria(AthMenu.class)
				.add(Restrictions.eq("root", ROOT))
				.setProjection(Projections.max("child")).uniqueResult());
		System.out.println("MAX ROOT :" + max);
		mymenu.setChild(max == null ? Integer.parseInt("" + ROOT + "0") : (max
				.intValue() + 1));

		init(mymenu, new EventListener() {

			@Override
			public void onEvent(Event arg0) throws Exception {
				onReloadTree(arg0);
			}
		});
		addWindow.setVisible(true);
		addWindow.onModal();
	}

	private void init(AthMenu menu, final EventListener eventListener) {
		this.menu = menu;
		addWindow.setTitle("Pendataan Menu");
		Common.clear(addWindow);
		Borderlayout borderlayout = new Borderlayout();
		Center center = new Center();
		center.setParent(borderlayout);
		center.setFlex(true);
		Grid grid = new Grid();
		grid.setParent(center);
		grid.setWidth("100%");
		grid.setHeight("100%");
		// grid.setOddRowSclass("non-odd");
		Columns columns = new Columns();
		columns.setParent(grid);

		Column column = new Column();
		column.setParent(columns);
		column.setWidth("20%");

		column = new Column();
		column.setParent(columns);
		column.setWidth("90%");

		Rows rows = new Rows();
		rows.setParent(grid);

		Row row = new Row();
		row.setStyle("border:0px;background: transparent;");
		row.setParent(rows);
		row.appendChild(new Label("Label"));
		row.appendChild(label = new Textbox(menu.getLabel()));
		label.setWidth("95%");

		row = new Row();
		row.setStyle("border:0px;background: transparent;");
		row.setParent(rows);
		row.appendChild(new Label("URL"));
		row.appendChild(url = new Textbox(menu.getUrl()));
		url.setWidth("95%");

		row.setStyle("border:0px;background: transparent;");
		row.setParent(rows);
		row.appendChild(new Label("Aktif"));
		row.appendChild(status = new Checkbox());
		status.setChecked(menu.getStatus() == null || menu.getStatus());

		South south = new South();
		south.setFlex(true);
		south.setParent(borderlayout);

		Toolbar toolbar = new Toolbar();
		toolbar.setHeight("30px");
		toolbar.setParent(south);
		Toolbarbutton cancel = new Toolbarbutton("Batal",
				"/include/img/icon-back.png");
		cancel.setTooltiptext("Tutup");
		cancel.addEventListener("onClick", new EventListener() {
			@Override
			public void onEvent(Event event) throws Exception {
				addWindow.setVisible(false);
			}
		});
		cancel.setParent(toolbar);
		Toolbarbutton save = new Toolbarbutton("Simpan",
				"/include/img/icon-save.png");
		save.setTooltiptext("Simpan");
		save.addEventListener("onClick", new EventListener() {
			@Override
			public void onEvent(Event event) throws Exception {
				if (onSave(event)) {
					// onSearchDefault(null);
					eventListener.onEvent(new Event("", null,
							MenuAction.this.menu));
					addWindow.setVisible(false);
				}
			}
		});
		save.setParent(toolbar);
		borderlayout.setParent(addWindow);

	}

	public boolean onSave(Event event) throws Exception {

		if (label.getValue().trim().equals("")) {
			Messagebox.show("Label harus diisi", "Peringatan", Messagebox.OK,
					Messagebox.EXCLAMATION);
			return false;
		}

		boolean i = checkKodeMenu();
		if (i) {
			Messagebox.show("Kode sudah ada di database", "Peringatan", 1,
					Messagebox.EXCLAMATION);
			return false;
		}

		Session session = HibernateUtil.currentSession();
		if (menu.getId() != null) {
			menu = (AthMenu) session.load(AthMenu.class, menu.getId());
		}

		menu.setLabel(label.getText().trim());
		menu.setStatus(status.isChecked());
		menu.setUrl(url.getValue());

		if (menu.getId() != null) {
			session.update(session.merge(menu));
		} else {
			session.save(menu);
		}
		// checkForChildsCopy(menu, menuTreeModel);
		return true;
	}

	public Boolean checkKodeMenu() {

		Integer kodeCount = null;
		Session session = HibernateUtil.currentSession();
		kodeCount = ((Number) session
				.createCriteria(AthMenu.class)
				.setProjection(Projections.count("id"))
				.add(Restrictions.eq("label", label.getValue().trim()))
				.add(this.menu.getId() == null ? Restrictions
						.sqlRestriction("1=1") : Restrictions.ne("id",
						this.menu.getId())).uniqueResult()).intValue();

		return !kodeCount.equals(0);
	}

	public void onReloadTree(Event event) throws Exception {

		menuTreeModel = new MenuTreeModel();
		tree.setModel(menuTreeModel);

		tree.setItemRenderer(new TreeitemRenderer() {

			@Override
			public void render(final Treeitem treeitem, Object arg1)
					throws Exception {
				final AthMenu menu = (AthMenu) arg1;

				try {
					final Treerow treerow = new Treerow();
					treerow.setParent(treeitem);

					new Treecell(menu.getLabel().toString()).setParent(treerow);

					Treecell treecell = new Treecell();
					treecell.setStyle("color:blue;text-align: right;");

					final Checkbox checkbox = new Checkbox();
					checkbox.setChecked(menu.getStatus() == null
							|| menu.getStatus());
					checkbox.setParent(treecell);
					checkbox.addEventListener("onCheck", new EventListener() {

						@Override
						public void onEvent(Event arg0) throws Exception {
							Session session = HibernateUtil.currentSession();
							// menu.setAktif(checkbox.isChecked());
							session.update(session.merge(menu));
						}
					});

					treecell.setParent(treerow);

					Treecell arg0 = new Treecell();
					arg0.setParent(treerow);
					Hbox toolbar = new Hbox();
					Toolbarbutton button = new Toolbarbutton("",
							"/include/img/icon-add.png");
					button.setTooltiptext("Tambah Data");
					button.setVisible(add);
					button.addEventListener("onClick", new EventListener() {
						@Override
						public void onEvent(Event event) throws Exception {

							AthMenu mymenu = (AthMenu) menu; // .clone();

							Session session = HibernateUtil.currentSession();

							Number max = ((Number) session
									.createCriteria(AthMenu.class)
									.add(Restrictions.eq("root",
											menu.getChild()))
									.setProjection(Projections.max("child"))
									.uniqueResult());
							System.out.println("MAX CHILD:" + max);
							System.out.println("GET ROOT:" + menu.getRoot());
							System.out.println("GET CHILD:" + menu.getChild());

							mymenu.setRoot(menu.getChild());
							mymenu.setChild(max == null ? Integer.parseInt(""
									+ menu.getChild() + "0")
									: (max.intValue() + 1));

							mymenu.setId(null);
							init(mymenu, new EventListener() {

								@Override
								public void onEvent(Event arg0)
										throws Exception {

									reloadTreeitem(treeitem, true);

								}
							});
							addWindow.setVisible(true);
							addWindow.onModal();
						}

					});
					button.setParent(toolbar);

					button = new Toolbarbutton("", "/include/img/icon-copy.png");
					button.setTooltiptext("Copy Data");
					button.setVisible(edit & add);
					button.addEventListener("onClick", new EventListener() {
						@Override
						public void onEvent(Event event) throws Exception {

							Session session = HibernateUtil.currentSession();
							Number max = ((Number) session
									.createCriteria(AthMenu.class)
									.add(Restrictions.eq("root", menu.getRoot()))
									.setProjection(Projections.max("child"))
									.uniqueResult()).longValue();

							max = max == null ? 0 : max;

							AthMenu mymenu = (AthMenu) menu; // .clone();

							mymenu.setRoot(menu.getRoot());
							mymenu.setChild(max.intValue() == 0 ? Integer
									.parseInt("" + menu.getRoot() + "0") : (max
									.intValue() + 1));

							mymenu.setId(null);
							init(mymenu, new EventListener() {

								@Override
								public void onEvent(Event arg0)
										throws Exception {

									reloadTreeitem(treeitem, true);
								}
							});
							addWindow.setVisible(true);
							addWindow.onModal();
						}

					});
					button.setParent(toolbar);

					button = new Toolbarbutton("", "/include/img/icon-edit.png");
					button.setTooltiptext("Rubah Data");
					button.setVisible(edit);
					button.addEventListener("onClick", new EventListener() {
						@Override
						public void onEvent(Event event) throws Exception {
							init(menu, new EventListener() {

								@Override
								public void onEvent(Event arg0)
										throws Exception {

									reloadTreeitem(treeitem, true);

								}
							});
							addWindow.setVisible(true);
							addWindow.onModal();
						}

					});
					button.setParent(toolbar);

					button = new Toolbarbutton("",
							"/include/img/icon-delete.png");
					button.setTooltiptext("Hapus Data");
					button.setVisible(delete
							&& menuTreeModel.getChildCount(menu) == 0);
					button.addEventListener("onClick", new EventListener() {
						@Override
						public void onEvent(Event event) throws Exception {
							Messagebox.show(
									"Apakah yakin ingin menghapus data ini ?",
									"Question", Messagebox.OK
											| Messagebox.CANCEL,
									Messagebox.QUESTION, new EventListener() {

										@Override
										public void onEvent(Event event)
												throws Exception {
											int i = new Integer(event.getData()
													.toString());
											if (i == Messagebox.OK) {
												try {

													Session session = HibernateUtil
															.currentSession();

													session.delete(session
															.merge(menu));

													reloadTreeitem(treeitem,
															true);
												} catch (Exception e) {
													e.printStackTrace();
													Messagebox.show("Data ini tidak dapat dihapus .., karena berelasi dengan data lainnya, error-nya adalah sbagai berikut:"
															+ e.getMessage());
												}

											}

										}
									});

						}
					});
					button.setParent(toolbar);
					toolbar.setParent(arg0);
				} catch (Exception e) {
					e.printStackTrace();
				}

			}
		});
	}

	private void reloadTreeitem(final Treeitem treeitem,
			final Boolean loadParent) {
		final Treeitem treeitemParent = loadParent ? treeitem.getParentItem()
				: treeitem;
		if (treeitemParent == null) {
			try {
				onReloadTree(null);
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			treeitemParent.unload();
			final Timer timer = new Timer(200);
			timer.setParent(page.getFirstRoot());
			timer.addEventListener("onTimer", new EventListener() {

				@SuppressWarnings({})
				@Override
				public void onEvent(Event arg0) throws Exception {
					treeitemParent.setOpen(true);
					treeitem.setOpen(true);
					timer.detach();
				}
			});

			timer.start();
		}
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void openChilds(final Treeitem treeitemParent, int max, int index) {
		if (max > index) {
			treeitemParent.setOpen(true);
			List treeitems = treeitemParent.getChildren();
			for (Object object : treeitems) {

				if (object instanceof Treechildren) {
					Treechildren treechildren = (Treechildren) object;
					List<Treeitem> mytreeitems = treechildren.getChildren();
					for (Treeitem treeitem : mytreeitems) {
						openChilds(treeitem, max, (++index));
					}

				}
			}
		}
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void closeChilds(final Treeitem treeitemParent) {
		treeitemParent.setOpen(false);
		List treeitems = treeitemParent.getChildren();
		for (Object object : treeitems) {

			if (object instanceof Treechildren) {
				Treechildren treechildren = (Treechildren) object;
				List<Treeitem> mytreeitems = treechildren.getChildren();
				for (Treeitem treeitem : mytreeitems) {
					closeChilds(treeitem);
				}

			}
		}
	}
}
